Skip to content

fix: filter secrets context from ignore-if-missing if: guard expression#45828

Merged
pelikhan merged 8 commits into
mainfrom
copilot/fix-ignore-if-missing-expression
Jul 16, 2026
Merged

fix: filter secrets context from ignore-if-missing if: guard expression#45828
pelikhan merged 8 commits into
mainfrom
copilot/fix-ignore-if-missing-expression

Conversation

Copilot AI commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

GitHub Actions rejects secrets.* in if: expressions at parse time — only github, needs, vars, env, inputs, steps, and runner contexts are valid there. When ignore-if-missing: true was set on a GitHub App config that used ${{ secrets.* }} for either credential, the compiler emitted an invalid guard like:

if: ${{ vars.APP_CLIENT_ID != '' && secrets.APP_PRIVATE_KEY != '' }}
#                                   ^ rejected by GitHub Actions

Changes

  • buildIgnoreIfMissingCondition — rewrote to filter out any ${{ secrets.* }}, ${{ jobs.* }}, or ${{ matrix.* }} expressions before building the &&-joined guard. Returns an empty string when all credentials use invalid contexts (step runs unconditionally, which is the correct fallback).
  • ifInvalidContextPrefixes + isValidIfContextExpression — new package-level blocklist and helper encoding which expression context prefixes are not allowed in if: conditions, with a reference to the GitHub Actions docs.
  • 4 callers updatedbuildGitHubAppTokenMintStepWithMeta, buildActivationAppTokenMintStep, buildPreActivationAppTokenMintStep, and buildDailyAICAppTokenMintStep now guard against the empty-string return before emitting an if: line.

Resulting behavior

client-id private-key Emitted if:
${{ vars.APP_ID }} ${{ secrets.KEY }} ${{ vars.APP_ID != '' }}
${{ vars.APP_ID }} ${{ vars.KEY }} ${{ vars.APP_ID != '' && vars.KEY != '' }}
${{ secrets.ID }} ${{ secrets.KEY }} (omitted — step runs unconditionally)

Copilot AI and others added 2 commits July 15, 2026 22:05
… expressions

GitHub Actions only allows github, needs, vars, env, inputs, steps, and runner
contexts in if: expressions. The secrets context is not allowed.

When buildIgnoreIfMissingCondition generates the step guard expression for
ignore-if-missing: true, it now filters out any wrapped ${{ secrets.* }}
values. Only expressions with valid if: contexts (vars, env, inputs, github,
steps, runner, etc.) are included in the condition. When all credential values
use the secrets context, no if: condition is emitted and the step runs
unconditionally (same as the workaround users had found).

Fixes: #44709

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
…ontextPrefixes

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix ignore-if-missing to generate valid if: expression fix: filter secrets context from ignore-if-missing if: guard expression Jul 15, 2026
Copilot AI requested a review from pelikhan July 15, 2026 22:06
@pelikhan
pelikhan marked this pull request as ready for review July 15, 2026 22:08
Copilot AI review requested due to automatic review settings July 15, 2026 22:08
@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Design Decision Gate 🏗️ completed the design decision gate check.

No ADR enforcement needed: PR #45828 does not have the 'implementation' label and has 81 new lines of code in business logic directories (below the 100-line threshold).

@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates GitHub App token guards to avoid unsupported secrets.* references in step conditions.

Changes:

  • Filters selected contexts from generated credential guards.
  • Omits empty guards across four token-mint paths.
  • Updates tests for secret-backed credentials.
Show a summary per file
File Description
pkg/workflow/safe_outputs_app_config.go Implements filtering and conditional guard emission.
pkg/workflow/compiler_pre_activation_job.go Handles empty pre-activation guards.
pkg/workflow/compiler_activation_daily_aic.go Preserves the daily AIC condition when credential guards are empty.
pkg/workflow/safe_outputs_app_test.go Updates safe-output guard tests.
pkg/workflow/skip_if_match_test.go Updates pre-activation guard expectations.
pkg/workflow/activation_github_token_test.go Updates activation guard expectations.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 6/6 changed files
  • Comments generated: 3
  • Review effort level: Medium

Comment thread pkg/workflow/safe_outputs_app_config.go Outdated
Comment thread pkg/workflow/safe_outputs_app_config.go Outdated
Comment thread pkg/workflow/safe_outputs_app_config.go Outdated
@github-actions github-actions Bot mentioned this pull request Jul 15, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two correctness issues + one consistency gap need resolution before merge

The core direction of this PR is correct — emitting secrets.* in if: expressions is a GitHub Actions parse error. But the implementation has gaps:

  1. isValidIfContextExpression only checks the leading prefix (see inline comment on line 67). A composite expression where an invalid context appears mid-string will silently pass and produce a broken if:.
  2. Empty-string return = unconditional execution, which directly defeats ignore-if-missing semantics when both credentials are secrets-based. The step will now fail at runtime instead of being skipped, which is worse than the bug being fixed (see inline comment on line 97).
  3. Inconsistent fallback behaviour across the four callers: buildDailyAICAppTokenMintStep has an else branch, but buildPreActivationAppTokenMintStep and the two in safe_outputs_app_config.go do not. Needs explicit documentation or alignment (see inline comment on compiler_pre_activation_job.go:43).

🔎 Code quality review by PR Code Quality Reviewer · 33.6 AIC · ⌖ 4.81 AIC · ⊞ 5.6K
Comment /review to run again

Comments that could not be inline-anchored

pkg/workflow/safe_outputs_app_config.go:67

isValidIfContextExpression only checks the leading prefix — a composite expression like ${{ github.actor != &#39;&#39; || secrets.TOKEN != &#39;&#39; }} passes this check (leading token is github.) but GitHub Actions will still reject the if: at parse time because secrets. appears in the expression body.

<details>
<summary>💡 Suggested fix</summary>

Use strings.Contains instead of strings.HasPrefix to catch invalid context references anywhere in the expression:

func isValidIfContextE</details>

<details><summary>pkg/workflow/safe_outputs_app_config.go:97</summary>

**Returning `&quot;&quot;` when all credentials are invalid-context breaks `ignore-if-missing` semantics** — when both `AppID` and `PrivateKey` reference `secrets.*`, every check is filtered out and the function returns `&quot;&quot;`. All callers then omit the `if:` guard entirely, making the token-mint step run unconditionally. If the secrets are not configured, the step will **fail at runtime** rather than skip. The whole point of `ignore-if-missing: true` is to skip when credentials are absent; silently runnin…

</details>

<details><summary>pkg/workflow/compiler_pre_activation_job.go:43</summary>

**No fallback `if:` guard when condition is empty, inconsistent with `compiler_activation_daily_aic.go`** — in `buildDailyAICAppTokenMintStep`, an empty condition correctly falls back to `maxDailyAICreditsConfiguredIfExpr`. Here in `buildPreActivationAppTokenMintStep`, an empty condition produces no `if:` at all (step always runs), with no equivalent fallback. If these two code paths are intentionally different, that should be documented; if not, this is a behavioural inconsistency.

&lt;details&gt;
…

</details>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fix is correct and complete.

What was changed and why it works:

  • buildIgnoreIfMissingCondition now filters out secrets.*, jobs.*, and matrix.* context expressions before building the &&-joined guard, matching the GitHub Actions rule that only github, needs, vars, env, inputs, steps, and runner are valid in if: conditions.
  • Returns an empty string when all credentials use invalid contexts, and all 4 callers were updated correctly (step runs unconditionally — the safe fallback).
  • Tests cover all three meaningful cases: both secrets (empty guard), mixed vars+secrets (vars-only guard), both vars (full guard).

Minor non-blocking note: In compiler_activation_daily_aic.go, the inner else and outer else both emit identical if: maxDailyAICreditsConfiguredIfExpr lines — slight duplication but not a bug.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · 13.2 AIC · ⌖ 5.2 AIC · ⊞ 5K

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skills-Based Review 🧠

Applied /diagnosing-bugs and /tdd — the fix is correct and well-targeted; two minor suggestions filed as inline comments.

📋 Key Themes & Highlights

Key Themes

  • jobs. and matrix. coverage gap — both prefixes are in ifInvalidContextPrefixes but have no test cases in TestBuildIgnoreIfMissingCondition.
  • Silent guard omission — when all credentials use secrets.*, the if: guard is silently dropped. The per-credential log line fires, but nothing signals at compile time that the whole guard was omitted.

Positive Highlights

  • ✅ Blocklist + helper pattern makes the invariant explicit and easy to extend.
  • ✅ Empty-string sentinel for "no guard" is adopted consistently across all four callers.
  • ✅ New test table covers the most important mixed-context scenario (vars + secrets).
  • ✅ PR description table cleanly documents the three behavioral cases.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · 33.5 AIC · ⌖ 4.58 AIC · ⊞ 6.7K
Comment /matt to run again

Comment thread pkg/workflow/safe_outputs_app_config.go Outdated
Comment thread pkg/workflow/safe_outputs_app_config.go Outdated
@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: 81/100 — Acceptable

Analyzed 6 test modifications: all design-focused, with 50% edge/error coverage and excellent multi-point integration testing.

📊 Metrics (6 tests)
Metric Value
Modified tests 6 (Go: 6, JS: 0)
✅ Design tests 6 (100%)
⚠️ Implementation tests 0 (0%)
Edge/error coverage 3 (50%)
Duplicate clusters 0
Inflation ⚠️ 4.7:1 (safe_outputs_app_test.go)
🚨 Violations 0
Test File Classification Signals
TestSafeOutputsAppIgnoreIfMissing safe_outputs_app_test.go:88 Design: Behavioral contract ✅ Verifies no secrets in if: guard; fallback token present
TestBuildIgnoreIfMissingCondition (4 cases) safe_outputs_app_test.go:140 Design: Unit + Edge cases ✅ Tests all context filtering scenarios (pure secrets, pure vars, mixed, literals)
TestActivationGitHubApp sub-test activation_github_token_test.go:151 Design: Integration ✅ Verifies fix applies across activation job
TestSkipIfMatchPreActivationJob sub-test skip_if_match_test.go:454 Design: Integration ✅ Verifies fix applies across pre-activation job
📋 Test Changes Summary

3 test files modified, 0 new tests, 6 tests updated:

  1. safe_outputs_app_test.go (+17, -3)

    • TestSafeOutputsAppIgnoreIfMissing: Updated assertions to verify NO secrets-based if: guard
    • TestBuildIgnoreIfMissingCondition: Expanded from 2 to 4 test cases:
      • Pure secrets → empty condition
      • Pure vars → both vars checked
      • Mixed (vars + secrets) → only valid contexts
      • Literals → properly escaped
  2. activation_github_token_test.go (+3, -1)

    • Updated sub-test to verify fix applies in activation job
  3. skip_if_match_test.go (+4, -2)

    • Updated sub-test to verify fix applies in pre-activation job
✨ Quality Highlights
  • Comprehensive context filtering coverage: All 4 scenarios tested (secrets-only, vars-only, mixed, literals)
  • Multi-point integration: Fix verified across safe_outputs, activation, and pre-activation jobs
  • Fallback logic verified: All tests confirm fallback to secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN
  • Descriptive comments added: Updated assertions include clear explanations of expected behavior
  • Table-driven expansion: 2 new edge cases added to unit test for better coverage

Verdict

APPROVED. 100% design tests (threshold: ≤30% implementation). Excellent edge/error coverage and multi-point integration testing. The test inflation (4.7:1) is acceptable for a table-driven test expansion that adds genuine behavioral coverage.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • awmgmcpg

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "awmgmcpg"

See Network Configuration for more information.

🧪 Test quality analysis by Test Quality Sentinel · 33.1 AIC · ⌖ 10.6 AIC · ⊞ 6.8K ·
Comment /review to run again

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test Quality Sentinel: 81/100. All tests are design-focused (100%) with excellent multi-point integration coverage across safe_outputs, activation, and pre-activation jobs. The table-driven expansion adds genuine behavioral coverage for context filtering edge cases.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, address unresolved review feedback, refresh the branch if needed, and rerun checks once updates are pushed.

Generated by 👨‍🍳 PR Sous Chef · 8.91 AIC · ⌖ 5.49 AIC · ⊞ 7.5K ·
Comment /souschef to run again

Copilot AI and others added 3 commits July 15, 2026 23:08
Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, address the unresolved review feedback (newest first: Copilot: #45828 (comment)), and rerun checks once the branch is up to date.

Generated by 👨‍🍳 PR Sous Chef · 9.41 AIC · ⌖ 6.79 AIC · ⊞ 7.5K ·
Comment /souschef to run again

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>

Copilot AI commented Jul 15, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please run the pr-finisher skill, address unresolved review feedback, refresh the branch if needed, and rerun checks once updates are pushed.

...

Updated in 7a5bc2a. The branch now preserves ignore-if-missing by rewriting unsupported secrets.*/jobs.* checks through step-local env aliases, keeps matrix.* valid in step if: expressions, and handles composite or bracket-notation context references. Local validation is green (make fmt, make lint, make test-unit, make test); CI on this new HEAD is still stale and needs a maintainer to re-trigger.

…-missing-expression

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>

Copilot AI commented Jul 15, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please run the pr-finisher skill, address the unresolved review feedback (newest first: Copilot: #45828 (comment)), and rerun checks once th...

Updated on current HEAD db79e34. I merged origin/main, verified the stale Copilot/GitHub Actions review threads against the current implementation, replied on each unresolved in-scope thread, and reran local validation successfully (make fmt, make lint, make test-unit, make test, make recompile). The PR branch is now up to date locally; CI on this HEAD is still unverified/stale and needs a maintainer-triggered rerun before merge.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, address any unresolved review feedback, and rerun checks once the branch is up to date.

Generated by 👨‍🍳 PR Sous Chef · 3.47 AIC · ⌖ 11.2 AIC · ⊞ 5.1K ·
Comment /souschef to run again

@github-actions

Copy link
Copy Markdown
Contributor

🤖 PR Triage

Field Value
Category bug
Risk medium
Score 70 / 100
Action fast_track

Score breakdown: Impact 35 + Urgency 22 + Quality 13

Fixes compiler bug: secrets.* context references in if: expressions were emitted for ignore-if-missing guards, causing GitHub Actions to reject workflows at parse time. Behavioral fix with tests (6 files). CI unknown — awaiting checks.

Run §29462479491

Generated by 🔧 PR Triage Agent · 189.6 AIC · ⌖ 5.52 AIC · ⊞ 5.6K ·

Copilot AI commented Jul 16, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please run the pr-finisher skill, address any unresolved review feedback, and rerun checks once the branch is up to date.

...

Checked current HEAD db79e34: there isn’t any new in-scope unresolved review feedback beyond the already-replied outdated threads, so no further code change was needed. I reran local validation successfully (make fmt, make lint, make test-unit, make test, make recompile, and make agent-report-progress); GitHub-side checks on this HEAD are still stale/ongoing and need a maintainer-triggered rerun before merge.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, address any unresolved review feedback, and rerun checks once the branch is up to date.

Generated by 👨‍🍳 PR Sous Chef · 9.13 AIC · ⌖ 6.02 AIC · ⊞ 5.1K ·
Comment /souschef to run again

Copilot AI commented Jul 16, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please run the pr-finisher skill, address any unresolved review feedback, and rerun checks once the branch is up to date.

...

Checked current HEAD db79e34: there isn’t any new in-scope unresolved review feedback beyond the already-replied outdated threads, so no further code change was needed. I reran local validation successfully in /home/runner/work/gh-aw/gh-aw (make fmt, make lint, make test-unit, make test, make recompile, and make agent-report-progress); the recent GitHub-side workflow runs on this head are still stale/action_required with no failed jobs exposed via logs, so CI on this HEAD remains unverified and needs a maintainer-triggered rerun before merge.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

\n@copilot please run the skill, address the unresolved review feedback (newest first: github-actions: #45828 (comment); github-actions: #45828 (comment); copilot-pull-request-reviewer: #45828 (comment); copilot-pull-request-reviewer: #45828 (comment); copilot-pull-request-reviewer: #45828 (comment)), and rerun checks once the branch is up to date.\n\n> Generated by \ud83c\udf73 PR Sous Chef

Generated by 👨‍🍳 PR Sous Chef · 4.65 AIC · ⌖ 9.69 AIC · ⊞ 7.5K ·
Comment /souschef to run again

@pelikhan
pelikhan merged commit 75347bf into main Jul 16, 2026
31 checks passed
@pelikhan
pelikhan deleted the copilot/fix-ignore-if-missing-expression branch July 16, 2026 04:22
@github-actions

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.82.10

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ignore-if-missing generates invalid if: expression using secrets context

4 participants